﻿using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace bowlingkata
{
    public class BowlingGame
    {
        public static int CalculateTotal(IEnumerable<int> rolls)
        {
            return Frame.CreateFramesFromRolls(rolls)
                        .Enrich_frames_with_score()
                        .Calc_total();
        }

        internal static IEnumerable<Frame> Enrich_frames_with_score(IEnumerable<Frame> frames)
        {
            return frames.Add_pins_in_frame()
                         .Add_bonus_for_spares()
                         .Add_bonus_for_strikes();
        }


        internal static IEnumerable<Frame> Add_pins_in_frame(IEnumerable<Frame> frames)
        {
            foreach (var f in frames)
            {
                f.AddPoints(f[0] + f[1]);
                yield return f;
            }
        }


        internal static IEnumerable<Frame> Add_bonus_for_spares(IEnumerable<Frame> frames)
        {
            var aFrames = frames.ToArray();
            for (var i = 0; i < aFrames.Length; i++)
            {
                var frame = aFrames[i];
                if (IsIndexOfRegularFrame(i) && frame.IsSpare)
                    frame.AddPoints(Calc_spare_bonus(aFrames, i));
                yield return frame;
            }
        }


        internal static IEnumerable<Frame> Add_bonus_for_strikes(IEnumerable<Frame> frames)
        {
            var aFrames = frames.ToArray();
            for (var i = 0; i < aFrames.Length; i++)
            {
                var frame = aFrames[i];
                if (IsIndexOfRegularFrame(i) && frame.IsStrike)
                    frame.AddPoints(Calc_strike_bonus(aFrames, i));
                yield return frame;
            }
        }


        internal static int Calc_total(IEnumerable<Frame> frames)
        {
            return frames.Where((frame, i) => IsIndexOfRegularFrame(i))
                         .Select(frame => frame.Score)
                         .Sum();

        }


        private static bool IsIndexOfRegularFrame(int i)
        {
            return i < 10;
        }


        private static int Calc_spare_bonus(Frame[] frames, int currentFrameIndex)
        {
            return frames[currentFrameIndex + 1][0];
        }

        private static int Calc_strike_bonus(Frame[] frames, int currentFrameIndex)
        {
            var bonus = frames[currentFrameIndex + 1][0] + frames[currentFrameIndex + 1][1];
            if (frames[currentFrameIndex + 1].IsStrike)
                bonus += frames[currentFrameIndex + 2][0];
            return bonus;
        }
    }
}
